﻿#pragma once

#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <algorithm>
#include <cmath>
#include <string>
#include <thread>
#include <vector>
#include <mutex>
#include "../cs2 dumper/client_dll.hpp"
#include "../cs2 dumper/offsets.hpp"
#include "../PlayerData/PlayerData.h"
#include "../messagebox/messagebox.h"
#include "../movement/movement.h"
#include "../ESP/vision.h"
#include "../../dll_main.h"
#include "../GameTrace/GameTrace.h"
#include "../function/KEY/KEY.h"
#include "../../cs2 dumper/server_dll.hpp"
#include "AimBot.h"

// 线程安全锁
static std::mutex g_targetMutex;
std::vector<TargetInfo> g_targetList;
uintptr_t g_lastTargetPawn;  // 上一个目标的pawn记录
// 添加模板前置声明
template<typename T>
bool SafeReadMemory(uintptr_t address, T* value, size_t size = sizeof(T));

Vector3 CalculateAimAngle(const Vector3& localPos, const Vector3& targetPos, const Vector3& currentAngles, float smoothFactor)
{
    Vector3 dir = targetPos - localPos;
    float length = dir.Length();
    if (length < 0.001f) {
        return currentAngles;
    }

    dir = dir / length;

    float targetYaw = atan2f(dir.y, dir.x) * (180.0f / static_cast<float>(M_PI));
    float targetPitch = atan2f(-dir.z, sqrtf(dir.x * dir.x + dir.y * dir.y)) * (180.0f / static_cast<float>(M_PI));

    Vector3 newAngles;

    if (smoothFactor <= 0.0f) {
        newAngles.x = targetPitch;
        newAngles.y = targetYaw;
    }
    else {
        float smoothFactor2 = std::clamp(0.4f - (smoothFactor * 0.015f), 0.05f, 0.35f);
        float pitchDiff = std::remainder(targetPitch - currentAngles.x, 360.0f);
        float yawDiff = std::remainder(targetYaw - currentAngles.y, 360.0f);

        newAngles.x = currentAngles.x + pitchDiff * smoothFactor2;
        newAngles.y = currentAngles.y + yawDiff * smoothFactor2;
    }

    newAngles.z = 0.0f;
    newAngles.x = std::clamp(newAngles.x, -89.0f, 89.0f);
    newAngles.y = std::remainder(newAngles.y, 360.0f);

    return newAngles;
}

int GetGameMode() {
    auto matchmakingBase = reinterpret_cast<std::uintptr_t>(GetModuleHandleA("matchmaking.dll"));
    auto gameTypePtr = (uint64_t**)(matchmakingBase + cs2_dumper::offsets::matchmaking_dll::dwGameTypes);
    auto getModeFunc = (*gameTypePtr)[20];
    using FN_GetMode = int64_t(__fastcall*)(void*);
    return ((FN_GetMode)getModeFunc)(gameTypePtr);
}


bool GetWeaponAccuracyInfo(PlayerData localPawn, uintptr_t client, float& accuracyPercentage)
{
    if (!IsValidPointer(localPawn.pawn) || !IsValidPointer(client))
        return false;

    uintptr_t weaponServices = *reinterpret_cast<uintptr_t*>(
        localPawn.pawn + cs2_dumper::schemas::client_dll::C_BasePlayerPawn::m_pWeaponServices);

    if (!weaponServices) return false;

    // 获取当前武器
    uintptr_t active_weapon_handle = *reinterpret_cast<uintptr_t*>(
        weaponServices + cs2_dumper::schemas::client_dll::CPlayer_WeaponServices::m_hActiveWeapon);

    auto activeWeapon = GetBaseEntityFromHandle(active_weapon_handle, client);
    if (!activeWeapon) return false;

    // 获取基础精度惩罚值
    float flBasePenalty = *reinterpret_cast<float*>(activeWeapon + cs2_dumper::schemas::client_dll::C_CSWeaponBase::m_fAccuracyPenalty);

    accuracyPercentage = flBasePenalty;

    return true;
}

bool set_view_angle(Vector3 Angle)
{
    static auto client = reinterpret_cast<uintptr_t>(GetModuleHandle(L"client.dll"));
    if (!client || !IsValidPointer(client))
        return false;

    uintptr_t viewAnglesAddr = client + cs2_dumper::offsets::client_dll::dwViewAngles;
    if (!IsValidPointer(viewAnglesAddr))
        return false;

    MEMORY_BASIC_INFORMATION mbi;
    if (!VirtualQuery(reinterpret_cast<LPCVOID>(viewAnglesAddr), &mbi, sizeof(mbi)) ||
        !(mbi.Protect & (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE))) {
        return false;
    }

    __try {
        *reinterpret_cast<Vector3*>(viewAnglesAddr) = Angle;
        return true;
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return false;
    }
}

bool IsValidPointer(uintptr_t pointer)
{
    if (pointer == 0 || pointer == 0xFFFFFFFF || pointer == 0xCCCCCCCC) {
        return false;
    }

    MEMORY_BASIC_INFORMATION mbi;
    if (VirtualQuery(reinterpret_cast<LPCVOID>(pointer), &mbi, sizeof(mbi))) {
        return !(mbi.Protect & (PAGE_NOACCESS | PAGE_GUARD));
    }
    return false;
}

template<typename T>
bool SafeReadMemory(uintptr_t address, T* value, size_t size)
{
    if (!IsValidPointer(address))
        return false;

    __try {
        memcpy(value, reinterpret_cast<const void*>(address), size);
        return true;
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return false;
    }
}

void AIMBOT(std::uintptr_t client)
{
    if (!client || !IsValidPointer(client))
        return;

    while (true)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));

        if (!all_settings::aimbot_anitaimbot::aimbot::open_aimbot.enabled)
            continue;

        auto& playerDataManager = PlayerDataManager::GetInstance();
        if (!IsValidPointer(reinterpret_cast<uintptr_t>(&playerDataManager)))
            continue;

        auto localPlayer = playerDataManager.GetLocalPlayerData();
        if (!localPlayer.pawn || localPlayer.health <= 0)
        {
            std::lock_guard<std::mutex> lock(g_targetMutex);
            g_lastTargetPawn = 0;
            continue;
        }

        uintptr_t matrixAddr = client + cs2_dumper::offsets::client_dll::dwViewMatrix;
        if (!IsValidPointer(matrixAddr))
            continue;

        float Matrix[16];
        if (!SafeReadMemory(matrixAddr, Matrix, sizeof(Matrix)))
            continue;

        if (WEAPON_NAMES.count(localPlayer.weaponID) == 0)
        {
            std::lock_guard<std::mutex> lock(g_targetMutex);
            g_lastTargetPawn = 0;
            continue;
        }

        auto& weaponSettings = all_settings::aimbot_anitaimbot::aimbot::aimbot_weapon_settings;
        if (weaponSettings.empty() || weaponSettings.find(0) == weaponSettings.end())
        {
            std::lock_guard<std::mutex> lock(g_targetMutex);
            g_lastTargetPawn = 0;
            continue;
        }

        auto& current_settings = weaponSettings[localPlayer.weaponID];
        auto& default_settings = weaponSettings[0];
        all_settings::aimbot_anitaimbot::aimbot::WeaponSettings temp_settings;

        if (current_settings.enabled) {
            temp_settings = current_settings;
        }
        else if (default_settings.enabled) {
            temp_settings = default_settings;
        }
        else {
            continue;
        }

        auto eyePosOpt = GetEyePos(localPlayer.pawn);
        if (!eyePosOpt.has_value())
            continue;

        Vector3 local_eye_pos = eyePosOpt.value();
        Vector3 currentViewAngles;
        uintptr_t viewAnglesAddr = client + cs2_dumper::offsets::client_dll::dwViewAngles;
        if (!SafeReadMemory(viewAnglesAddr, &currentViewAngles, sizeof(Vector3)))
            continue;

        float accuracyPercentage;
        if (!GetWeaponAccuracyInfo(localPlayer, client, accuracyPercentage))
        {
            continue;
        }

        MessageWindow::AddColoredMessage("ss%.6f", accuracyPercentage);

        float radius = temp_settings.fov * 4;
        if (localPlayer.isScoped) {
            radius = radius * 2;
        }

        std::vector<TargetInfo> tempTargetList;
        auto Players = playerDataManager.GetPlayersData();
        if (Players.empty())
        {
            std::lock_guard<std::mutex> lock(g_targetMutex);
            g_lastTargetPawn = 0;
            continue;
        }
        int gameMode = GetGameMode();
        if (!gameMode)
        {   
            gameMode = 2;
        }

        for (const auto& player : Players)
        {
            if (!player.pawn || player.health <= 0)
                continue;

            if (gameMode != 2 && player.team == localPlayer.team)
            {
                continue;
            }

            int selectedBoneID = GetSelectedBoneID(temp_settings.bone_settings);
            auto headPosOpt = BonePos(player.pawn, selectedBoneID);
            if (!headPosOpt.has_value())
                continue;

            Vector3 headPos2d{};
            if (WorldToScreen(headPosOpt.value(), headPos2d, Matrix, ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y))
            {
                float screenDistance = sqrtf(
                    powf(headPos2d.x - ImGui::GetIO().DisplaySize.x / 2.0f, 2) +
                    powf(headPos2d.y - ImGui::GetIO().DisplaySize.y / 2.0f, 2)
                );

                if (temp_settings.fov == 180 || screenDistance <= radius)
                {
                    CGameTrace pGameTrace = Ray::TraceShape(local_eye_pos, headPosOpt.value(), localPlayer.pawn, 0xC3003);
                    if (pGameTrace.pHitEntity == (void*)player.pawn)
                    {
                        tempTargetList.emplace_back(TargetInfo{
                            player.name,
                            screenDistance,
                            headPosOpt.value(),
                            player,
                            });
                    }
                }
            }
        }

        {
            std::lock_guard<std::mutex> lock(g_targetMutex);
            g_targetList = std::move(tempTargetList);

            if (g_targetList.empty())
            {
                g_lastTargetPawn = 0;
                continue;
            }

            auto bestTarget = std::min_element(g_targetList.begin(), g_targetList.end(),
                [](const TargetInfo& a, const TargetInfo& b) {
                    return a.distance < b.distance;
                });

            if (bestTarget == g_targetList.end())
            {
                g_lastTargetPawn = 0;
                continue;
            }

            g_lastTargetPawn = bestTarget->pawn.pawn;
            float smoothSetting = temp_settings.aimbot_smooth;
            Vector3 newAngles = CalculateAimAngle(
                local_eye_pos,
                bestTarget->headPos,
                currentViewAngles,
                smoothSetting
            );

            if (bestTarget->pawn.health > 0 && set_view_angle(newAngles))
            {
                if (all_settings::aimbot_anitaimbot::aimbot::autofire &&
                    localPlayer.speed <= 40 &&
                    bestTarget->distance <= 5)
                {
                    engine_client->execute_client_cmd("+attack");
                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
                    engine_client->execute_client_cmd("-attack");

                    if (bestTarget->pawn.health <= 0)
                    {
                        g_lastTargetPawn = 0;
                    }
                }
            }
        }
    }
}

void Aim_bot_Run()
{
    const auto client = reinterpret_cast<std::uintptr_t>(GetModuleHandleA("client.dll"));
    if (!client || !IsValidPointer(client))
        return;

    std::thread AIMBOTThread(AIMBOT, client);
    AIMBOTThread.detach();
}